package org.example.gxpt.service.impl;

import org.example.gxpt.common.constant.JwtClaimsConstant;
import org.example.gxpt.common.constant.LoginRoleConstant;
import org.example.gxpt.common.constant.RedisConstant;
import org.example.gxpt.common.constant.RoleConstant;
import org.example.gxpt.common.context.LoginContext;
import org.example.gxpt.common.properties.JwtProperties;
import org.example.gxpt.common.properties.RedisProperties;
import org.example.gxpt.common.utils.JwtUtil;
import org.example.gxpt.mapper.ShowroomMapper;
import org.example.gxpt.mapper.UserRoleMapper;
import org.example.gxpt.pojo.dto.LoginByPhoneDTO;
import org.example.gxpt.pojo.dto.LoginDTO;
import org.example.gxpt.pojo.entity.*;
import org.example.gxpt.pojo.userdetails.LoginUser;
import org.example.gxpt.pojo.vo.*;
import org.example.gxpt.service.LoginService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.security.authentication.AuthenticationManager;
import org.springframework.security.authentication.UsernamePasswordAuthenticationToken;
import org.springframework.security.core.Authentication;
import org.springframework.security.crypto.password.PasswordEncoder;
import org.springframework.stereotype.Service;

import java.util.HashMap;
import java.util.Map;
import java.util.Objects;
import java.util.concurrent.TimeUnit;

@Service
public class LoginServiceImpl implements LoginService {

    @Autowired
    private UserRoleMapper userRoleMapper;
    @Autowired
    private AuthenticationManager authenticationManager;
    @Autowired
    private JwtProperties jwtProperties;
    @Autowired
    private RedisTemplate redisTemplate;
    @Autowired
    private RedisProperties redisProperties;
    @Autowired
    private PasswordEncoder passwordEncoder;
    @Autowired
    private ShowroomMapper showroomMapper;

    @Override
    public LoginVO login(LoginDTO loginDTO) {

        UserRole userRole = userRoleMapper.selectByUsername(loginDTO.getUsername());
        //存储当前登录用户的角色信息，在UserDetailsServiceImpl中取出用于判断当前登录用户的角色，从对应的mapper中查询
        if(userRole.getRole().equals(RoleConstant.USER)) LoginContext.setCurrentRole(LoginRoleConstant.USER);
        else if(userRole.getRole().equals(RoleConstant.INSTRUMENT_ADMIN)) LoginContext.setCurrentRole(LoginRoleConstant.INSTRUMENT_ADMIN);
        else if(userRole.getRole().equals(RoleConstant.SHOWROOM_ADMIN)) LoginContext.setCurrentRole(LoginRoleConstant.SHOWROOM_ADMIN);
        else if(userRole.getRole().equals(RoleConstant.SYSTEM_ADMIN)) LoginContext.setCurrentRole(LoginRoleConstant.SYSTEM_ADMIN);
        else throw new RuntimeException("登录失败");

        //AuthenticationManager authenticate进行认证
        UsernamePasswordAuthenticationToken authenticationToken =
                new UsernamePasswordAuthenticationToken(loginDTO.getUsername(), loginDTO.getPassword());
        Authentication authenticate = authenticationManager.authenticate(authenticationToken);

        //如果认证没通过，给出对应提示
        if(Objects.isNull(authenticate)){
            throw new RuntimeException("登录失败");
        }

        return getLoginVO(authenticate, userRole);
    }

    private LoginVO getLoginVO(Authentication authenticate, UserRole userRole) {
        LoginUser loginUser = (LoginUser) authenticate.getPrincipal();
        LoginVO loginVO = new LoginVO();
        if(userRole.getRole().equals(RoleConstant.USER)) {
            //如果认证通过，使用生成一个jwt，存入loginVO中返回
            User user = loginUser.getUser();
            //生成jwt令牌
            Map<String, Object> claims = new HashMap<>();
            claims.put(JwtClaimsConstant.ROLE, RoleConstant.USER);
            claims.put(JwtClaimsConstant.ID, user.getId());
            String token = JwtUtil.createJWT(
                    jwtProperties.getSecretKey(),
                    jwtProperties.getTtl(),
                    claims);
            loginVO = LoginVO.builder()
                    .id(user.getId())
                    .name(user.getName())
                    .username(user.getUsername())
                    .token(token)
                    .avatar(user.getAvatar())
                    .role(RoleConstant.USER)
                    .build();
            //把完整的用户信息存入redis key:userid value:User对象
            redisTemplate.opsForValue().set(RedisConstant.LOGIN_USER + user.getId().toString(), loginUser, redisProperties.getTtl(), TimeUnit.MILLISECONDS);
        }
        else if(userRole.getRole().equals(RoleConstant.INSTRUMENT_ADMIN)){
            InstrumentAdmin instrumentAdmin = loginUser.getInstrumentAdmin();

            //生成jwt令牌
            Map<String, Object> claims = new HashMap<>();
            claims.put(JwtClaimsConstant.ROLE, RoleConstant.INSTRUMENT_ADMIN);
            claims.put(JwtClaimsConstant.ID, instrumentAdmin.getId());
            String token = JwtUtil.createJWT(
                    jwtProperties.getSecretKey(),
                    jwtProperties.getTtl(),
                    claims);

            Showroom showroom = showroomMapper.getShowroomById(instrumentAdmin.getShowroomId());
            if (Objects.isNull(showroom)) throw new RuntimeException("展厅不存在");

            loginVO = LoginVO.builder()
                    .id(instrumentAdmin.getId())
                    .name(instrumentAdmin.getName())
                    .username(instrumentAdmin.getUsername())
                    .token(token)
                    .avatar(instrumentAdmin.getAvatar())
                    .showroomId(instrumentAdmin.getShowroomId())
                    .showroomName(showroom.getName())
                    .role(RoleConstant.INSTRUMENT_ADMIN)
                    .build();

            //把完整的用户信息存入redis key:userid value:User对象
            redisTemplate.opsForValue().set(RedisConstant.LOGIN_INSTRUMENT_ADMIN + instrumentAdmin.getId().toString(), loginUser, redisProperties.getTtl(), TimeUnit.MILLISECONDS);
        }
        else if(userRole.getRole().equals(RoleConstant.SHOWROOM_ADMIN)){

            ShowroomAdmin showroomAdmin = loginUser.getShowroomAdmin();

            //生成jwt令牌
            Map<String, Object> claims = new HashMap<>();
            claims.put(JwtClaimsConstant.ROLE, RoleConstant.SHOWROOM_ADMIN);
            claims.put(JwtClaimsConstant.ID, showroomAdmin.getId());
            String token = JwtUtil.createJWT(
                    jwtProperties.getSecretKey(),
                    jwtProperties.getTtl(),
                    claims);

            Showroom showroom = showroomMapper.getShowroomById(showroomAdmin.getShowroomId());
            if (Objects.isNull(showroom)) throw new RuntimeException("展厅不存在");

            loginVO = LoginVO.builder()
                    .id(showroomAdmin.getId())
                    .name(showroomAdmin.getName())
                    .username(showroomAdmin.getUsername())
                    .token(token)
                    .avatar(showroomAdmin.getAvatar())
                    .showroomId(showroomAdmin.getShowroomId())
                    .showroomName(showroom.getName())
                    .role(RoleConstant.SHOWROOM_ADMIN)
                    .build();

            //把完整的用户信息存入redis
            redisTemplate.opsForValue().set(RedisConstant.LOGIN_SHOWROOM_ADMIN + showroomAdmin.getId().toString(), loginUser, redisProperties.getTtl(), TimeUnit.MILLISECONDS);
        }
        else if(userRole.getRole().equals(RoleConstant.SYSTEM_ADMIN)){
            SystemAdmin systemAdmin = loginUser.getSystemAdmin();

            //生成jwt令牌
            Map<String, Object> claims = new HashMap<>();
            claims.put(JwtClaimsConstant.ROLE, RoleConstant.SYSTEM_ADMIN);
            claims.put(JwtClaimsConstant.ID, systemAdmin.getId());
            String token = JwtUtil.createJWT(
                    jwtProperties.getSecretKey(),
                    jwtProperties.getTtl(),
                    claims);

            loginVO = LoginVO.builder()
                    .id(systemAdmin.getId())
                    .username(systemAdmin.getUsername())
                    .token(token)
                    .name(systemAdmin.getName())
                    .avatar(systemAdmin.getAvatar())
                    .role(RoleConstant.SYSTEM_ADMIN)
                    .build();

            //存入redis
            redisTemplate.opsForValue().set(RedisConstant.LOGIN_SYSTEM_ADMIN + systemAdmin.getId().toString(),
                    loginUser, redisProperties.getTtl(), TimeUnit.MILLISECONDS);

        }
        LoginContext.removeCurrentRole();
        return loginVO;
    }

    @Override
    public LoginVO loginByPhone(LoginByPhoneDTO loginByPhoneDTO) {

        UserRole userRole = userRoleMapper.selectByPhone(loginByPhoneDTO.getPhone());
        try {
            //存储当前登录用户的角色信息，在UserDetailsServiceImpl中取出用于判断当前登录用户的角色，从对应的mapper中查询
            if(userRole.getRole().equals(RoleConstant.USER)) LoginContext.setCurrentRole(LoginRoleConstant.USER_PHONE);
            else if(userRole.getRole().equals(RoleConstant.INSTRUMENT_ADMIN)) LoginContext.setCurrentRole(LoginRoleConstant.INSTRUMENT_ADMIN_PHONE);
            else if(userRole.getRole().equals(RoleConstant.SHOWROOM_ADMIN)) LoginContext.setCurrentRole(LoginRoleConstant.SHOWROOM_ADMIN_PHONE);
            else if(userRole.getRole().equals(RoleConstant.SYSTEM_ADMIN)) LoginContext.setCurrentRole(LoginRoleConstant.SYSTEM_ADMIN_PHONE);
            else throw new RuntimeException("登录失败");
        } catch (NullPointerException e) {
            throw new RuntimeException("手机号不存在");
        }

        //AuthenticationManager authenticate进行认证
        UsernamePasswordAuthenticationToken authenticationToken =
                new UsernamePasswordAuthenticationToken(loginByPhoneDTO.getPhone(), loginByPhoneDTO.getPassword());
        Authentication authenticate = authenticationManager.authenticate(authenticationToken);

        //如果认证没通过，给出对应提示
        if(Objects.isNull(authenticate)){
            throw new RuntimeException("登录失败");
        }

        return getLoginVO(authenticate, userRole);
    }
}
